/**
 @file sys_usw_fpa.h

 @date 2016-08-1

 @version v3.0

*/
#ifndef _SYS_USW_FPA_H
#define _SYS_USW_FPA_H

#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "ctc_const.h"


/***************************************************************
 *
 *  Defines and Macros
 *
 ***************************************************************/
#define FPA_PRIORITY_HIGHEST  0xFFFFFFFF
#define FPA_PRIORITY_LOWEST   0
#define FPA_PRIORITY_DEFAULT  1

#define REORDE_TYPE_NONE     0
#define REORDE_TYPE_SCATTER     1
#define REORDE_TYPE_DECREASE    2
#define REORDE_TYPE_INCREASE    3

/* pe is ctc_fpa_entry_t */
#define FPA_OUTER_ENTRY(pe)          ((uint8 *) pe - (fpa->offset))
/*#define FPA_INNER_ENTRY(i) ( (ctc_fpa_entry_t*) ( (pb->entries[i]) + (fpa->offset) ))*/
#define FPA_INNER_ENTRY(i)           (pb->entries[i])
#define PREV_IDX(idx, step)          ((idx) - (step))
#define NEXT_IDX(idx, step)          ((idx) + (step))
#define TRIGGER_REORDER      25
#define TRIGGER_PRESS        10
#define DO_REORDER(move_num, all)    ((move_num) > ((all) / TRIGGER_REORDER))
#define DO_PRESS(move_num)      ((move_num) >= TRIGGER_PRESS)
#define FPA_INVALID_INDEX    (-1)
#define FPA_FREE_COUNT(fpa_size)     (((pb->sub_free_count[fpa_size])>(pb->sub_rsv_count[fpa_size]))?((pb->sub_free_count[fpa_size])-(pb->sub_rsv_count[fpa_size])):0)

#define SYS_FPA_DBG_OUT(level, FMT, ...) \
    CTC_DEBUG_OUT(fpa, fpa, FPA, level, FMT, ## __VA_ARGS__)

#define SYS_FPA_DBG_FUNC() \
    SYS_FPA_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__)

#define SYS_FPA_DBG_INFO(FMT, ...) \
    SYS_FPA_DBG_OUT(CTC_DEBUG_LEVEL_INFO, FMT, ## __VA_ARGS__)

#define SYS_FPA_DBG_PARAM(FMT, ...) \
    SYS_FPA_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, FMT, ## __VA_ARGS__)

#define SYS_FPA_DBG_ERROR(FMT, ...) \
    SYS_FPA_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, FMT, ## __VA_ARGS__)
#define SYS_FPA_DBG_DUMP(FMT, ...) \
    SYS_FPA_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, FMT, ## __VA_ARGS__)

typedef enum
{
    CTC_FPA_KEY_SIZE_80   = 0,
    CTC_FPA_KEY_SIZE_160  = 1,
    CTC_FPA_KEY_SIZE_320  = 2,
    CTC_FPA_KEY_SIZE_640  = 3,
    CTC_FPA_KEY_SIZE_NUM
}ctc_fpa_key_size_t;

typedef struct
{
    uint16 t_idx; /* target index */
    uint16 o_idx; /* old index */
}_fpa_target_t;

typedef struct
{
    uint32      entry_id; /* entry id*/
    uint32      priority; /* entry priority. or hash ad index. */
    uint32      offset_a; /* key index. max: 2 local_chips*/
    uint8       flag;      /* entry flag, FPA_ENTRY_FLAG_xxx */
    uint8       step;
    uint8       real_step;
	uint8       key_size;
}ctc_fpa_entry_t;

struct ctc_fpa_block_s
{
    uint16      entry_count;  /* entry count on each block. uint16 is enough.*/
    uint16      free_count;   /* entry count left on each block*/

    uint16      start_offset[CTC_FPA_KEY_SIZE_NUM];
    uint16      sub_entry_count[CTC_FPA_KEY_SIZE_NUM];
    uint16      sub_free_count[CTC_FPA_KEY_SIZE_NUM];
    uint16      sub_rsv_count[CTC_FPA_KEY_SIZE_NUM];    /*rsv count can not be taken when adjust resource*/

    uint8       cur_trend[CTC_FPA_KEY_SIZE_NUM];
    uint32      increase_trend[CTC_FPA_KEY_SIZE_NUM];
    uint32      decrease_trend[CTC_FPA_KEY_SIZE_NUM];
    uint32      last_priority[CTC_FPA_KEY_SIZE_NUM];
    uint32      move_num[CTC_FPA_KEY_SIZE_NUM];

    uint8  slice_id;
    uint8  same_size;               /* all key use same size in one block and key size determine block num used */
    uint8  part;                    /* current block id */
    uint8  part_num;                /* block num used */
    uint32 base;                    /* entry index base for block merge */
    struct ctc_fpa_block_s* next;   /* block num > 1, linklist all fpa block */
    struct ctc_fpa_block_s * vblock; /*virtual block*/

    ctc_fpa_entry_t** entries;      /* pointer to entry*/
};
typedef struct ctc_fpa_block_s ctc_fpa_block_t;

#define CTC_FPA_BUILD_BLOCK_INFO(block_info, _key_size, _start_move_num, _sub_count_vary, _key160_count)    {\
    block_info.key_size = _key_size;\
    block_info.start_move_num = _start_move_num;\
    block_info.sub_count_vary = _sub_count_vary;\
    block_info.key160_count = _key160_count;\
    block_info.key160_count_valid = 0;\
}
struct ctc_fpa_block_info_s
{
    uint8 key_size;
    int16 start_move_num;
    int16 sub_count_vary;
    int16 key160_count;
	uint8 key160_count_valid;
};
typedef struct ctc_fpa_block_info_s ctc_fpa_block_info_t;

typedef int32 (*fpa_get_info_by_pe_fn)  (uint8 lchip, ctc_fpa_entry_t* pe, ctc_fpa_block_t** pb);
typedef int32 (*fpa_entry_move_hw_fn)   (uint8 lchip, ctc_fpa_entry_t* pe, int32 new_offset);

typedef struct
{
    fpa_get_info_by_pe_fn  get_info_by_pe;
    fpa_entry_move_hw_fn   entry_move_hw;
    uint8                  lchip;
    uint8                  offset; /* fpa_entry offset to user_entry struct's head.*/
    uint8                  mode;    /*fpa mode: 0-default, 1-for program*/
}ctc_fpa_t;


/*
 *move entry to a new place with amount steps.
 */
#define FPA_ENTRY_FLAG_UNINSTALLED  0
#define FPA_ENTRY_FLAG_INSTALLED    1


extern int32
fpa_usw_set_entry_prio(ctc_fpa_t* fpa, ctc_fpa_entry_t* pe, ctc_fpa_block_t* pb, uint8 key_size, uint32 prio);

extern int32
fpa_usw_alloc_offset(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 key_size, uint32 prio, uint32* block_index);

extern int32
fpa_usw_free_offset(ctc_fpa_block_t* pb, uint32 block_index);

extern int32
fpa_usw_scatter(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info);

extern int32
fpa_usw_increase(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info);

extern int32
fpa_usw_decrease(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info);

extern ctc_fpa_t*
fpa_usw_create(uint8 lchip,
                fpa_get_info_by_pe_fn fn1,
                fpa_entry_move_hw_fn fn2,
                uint8 offset);


int32
fpa_get_index_by_pe_idx(uint16 block_entry_count, uint16 sub_entry_count_160, int32 pe_idx);

int32
fpa_get_index_by_fpa_idx(ctc_fpa_block_t* pb, int32 fpa_idx);

ctc_fpa_block_t*
fpa_get_local_info_by_fpa_idx(ctc_fpa_block_t* pb, int32 fpa_idx, int32* p_local_idx);

extern void
fpa_usw_free(ctc_fpa_t* fpa);
extern int32
fpa_usw_reorder_virtual(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 type, ctc_fpa_block_info_t* p_info);
#ifdef __cplusplus
}
#endif

#endif

